﻿#include <XanaduCore/XLog.h>
#include <XanaduCore/XDateTime.h>


// Global log level
static EXANADU_LOG_LEVEL			_globalLogLevel = kXANADU_LOG_LEVEL_FULL;

// Output log
void XanaduStreamOutput(EXANADU_LOG_LEVEL _Level, const char* _Message) noexcept
{
#if defined(_XANADU_LOG_ENABLE)
	auto		vPrefixString = XString("[") + XDateTime::currentMillisecondToString() + XString("]");
	switch (_Level)
	{
		case kXANADU_LOG_LEVEL_FULL:
			vPrefixString += " [FULL] ";
			break;
		case kXANADU_LOG_LEVEL_DEBUG:
			vPrefixString += " [DEBUG] ";
			break;
		case kXANADU_LOG_LEVEL_INFO:
			vPrefixString += " [INFO] ";
			break;
		case kXANADU_LOG_LEVEL_WARNING:
			vPrefixString += " [WARNING] ";
			break;
		case kXANADU_LOG_LEVEL_ERROR:
			vPrefixString += " [ERROR] ";
			break;
		case kXANADU_LOG_LEVEL_FATAL:
			vPrefixString += " [FATAL] ";
			break;
		default:
			vPrefixString += " [UNKNOWN] ";
			break;
	}
	vPrefixString += _Message;
	vPrefixString += "\n";
#if defined(_XANADU_SYSTEM_WINDOWS)
	std::printf("%ls", vPrefixString.toWString().data());
#else
	std::printf("%s", vPrefixString.data());
#endif

#else
	XANADU_UNPARAMETER(_Level);
	XANADU_UNPARAMETER(_Format);
#endif
}



// constructor
XLog::XLog() noexcept = default;

// destructor
XLog::~XLog() noexcept = default;



// Set the current log level, which is kXANADU_LOG_LEVEL_FULL by default
void XLog::setLogLevel(EXANADU_LOG_LEVEL _Level) noexcept
{
	_globalLogLevel = _Level;
}



// Outputs the log at the specified level
void XLog::output(EXANADU_LOG_LEVEL _Level, const char* _Format, ...) noexcept
{
#if defined(_XANADU_LOG_ENABLE)
	if(_Level < _globalLogLevel)
	{
		return;
	}

	auto		vString = static_cast<char*>(nullptr);
	va_list		vArgs1;
	va_list		vArgs2;
	va_start(vArgs1, _Format);
	va_copy(vArgs2, vArgs1);
	auto		vSize = std::vsnprintf(nullptr, 0, _Format, vArgs1);
	if(vSize > 0)
	{
		vString = new(std::nothrow) char[vSize + 1];
		if(vString)
		{
			std::vsnprintf(vString, vSize + 1, _Format, vArgs2);
		}
	}
	va_end(vArgs1);
	va_end(vArgs2);

	if(vString)
	{
		XanaduStreamOutput(_Level, vString);
		delete[] vString;
	}
#else
	XANADU_UNPARAMETER(_Level);
	XANADU_UNPARAMETER(_Format);
#endif
}

// Outputs the log at the specified level
void XLog::output(EXANADU_LOG_LEVEL _Level, const XString& _Format) noexcept
{
#if defined(_XANADU_LOG_ENABLE)
	if(_Level < _globalLogLevel)
	{
		return;
	}

	XanaduStreamOutput(_Level, _Format.data());
#else
	XANADU_UNPARAMETER(_Level);
	XANADU_UNPARAMETER(_Format);
#endif
}
